import { SetMeshOverlayCommand } from "../command/mesh.command"
import { SceneChildType } from "../enum/scene.enum"
import re from "../packages/60039"
import GridPlaneCursor from "./GridPlaneCursor"
import * as THREE from "three"
import RenderLayers from "../utils/RenderLayers"
import TextureLoader from "../loader/TextureLoader"
import Vectors from "../three/Vectors"
import Te from "../math/19674"
import P from "../math/27687"
import SnappablePointer from "./SnappablePointer"
import CameraData from "../data/CameraData"
import WebGLScene from "../three/WebGLScene"
import RenderToTextureModule from "../module/RenderToTextureModule"
import EngineContext from "../EngineContext"
import CommandBinder from "../CommandBinder"
import ConstrainedHit from "../utils/ConstrainedHit"
export default class IntersectionVisualizer {
  mobile: boolean
  pointer: SnappablePointer
  sceneInfo: { cameraData: CameraData; playerCamera: THREE.PerspectiveCamera; scene: WebGLScene }
  renderToTexture: RenderToTextureModule
  getLayer: EngineContext["getRenderLayer"]
  issueCommand: CommandBinder["issueCommand"]
  editing: boolean
  editingStateChange: boolean
  setOverlay: (e: any) => void
  setupCursorRenderCamera: () => { camera: THREE.PerspectiveCamera; update: (t: any, i: any, s: any) => void }
  rttView: THREE.WebGLRenderTarget
  cursorMesh: GridPlaneCursor
  renderIntersection: (e: any, t: any, n: any) => void
  hit: ConstrainedHit
  constructor(e, t, i, s, n, r, o: () => boolean) {
    this.mobile = e
    this.pointer = t
    this.sceneInfo = i
    this.renderToTexture = s
    this.getLayer = n
    this.issueCommand = r
    this.editing = !1
    this.editingStateChange = !1
    this.setOverlay = e => {
      this.issueCommand(new SetMeshOverlayCommand({ color: e ? SetMeshOverlayCommand.COLOR_DIM : null }))
    }
    this.setupCursorRenderCamera = () => {
      const e = new THREE.PerspectiveCamera(re.X7.perspective.fov, 1, 0.1, 100)
      e.name = "Cursor Peek Camera"
      const t = RenderLayers.ALL,
        i = ["measurement-mode", "measurement3d"]
      for (const e of i) t.removeLayers(this.getLayer(e))
      e.layers.mask = t.mask
      e.updateProjectionMatrix()
      return {
        camera: e,
        update: (t, i, s) => {
          e.fov = t
          e.near = i
          e.far = s
          e.updateProjectionMatrix()
        }
      }
    }
    const a = TextureLoader("./images/scope.svg")
    const h = new THREE.Vector2()
    const l = e => {
      const t = this.rttView.height
      const i = this.rttView.width
      const s = this.sceneInfo.cameraData
      let n = t / 2
      const r = -i / 2
      n = e.y < t / 2 + n ? t + n : -n
      const o = e.x + r
      const a = s.height - e.y - n
      return h.set(o, a)
    }
    this.cursorMesh = new GridPlaneCursor(this.sceneInfo.scene, this.getLayer("cursor-mesh"))
    this.cursorMesh.setVisible(!1)
    const d = new THREE.Vector3()
    const c = new THREE.Quaternion()
    const u = new THREE.Vector2()
    let p,
      g,
      m = o(),
      w = re.X7.perspective
    this.renderIntersection = (e, t, n) => {
      p || ((g = this.setupCursorRenderCamera()), (p = g.camera), g.update(re.X7.perspective.fov, 0.1, 100)),
        m !== o() && ((w = o() ? re.X7.ortho : re.X7.perspective), this.cursorMesh.scale(w.scale), g.update(w.fov, 0.1, 100), (m = o()))
      const r = this.editingStateChange ? 1 : re.X7.smoothness
      if (t) {
        if ((i.playerCamera.getWorldPosition(d), i.playerCamera.getWorldQuaternion(c), o())) {
          const e = i.cameraData.zoom(),
            s = Te.dS(e, w.thresholdClose, w.thresholdFar, w.offsetClose, w.offsetFar)
          p.position.copy(t.point).addScaledVector(Vectors.UP, s), p.quaternion.copy(c)
        } else {
          const e = Te.dS(t.distance, w.thresholdClose, w.thresholdFar, w.offsetClose, w.offsetFar),
            i = d.sub(t.point).setLength(e).add(t.point)
          p.position.lerp(i, r), p.lookAt(t.point)
        }
        p.updateMatrixWorld(),
          re.E0 && this.setOverlay(!1),
          s.render(e, i.scene.scene, p),
          re.E0 && this.setOverlay(!0),
          u.lerp(l(n), r),
          s.renderToScreen(e, !1, u, a)
      }
      this.editingStateChange = !1
    }
  }
  init() {}
  dispose() {}
  activate() {
    this.sceneInfo.scene.addChild(SceneChildType.Root, this.cursorMesh.container)
    const e = this.mobile ? re.ox.mobileSize : this.sceneInfo.cameraData.height > re.ox.highResThreshold ? re.ox.desktopSizeHighRes : re.ox.desktopSize
    this.rttView = this.renderToTexture.createRenderTarget2D(e, e, { format: THREE.RGBFormat }, !1)
  }
  setMeasuringPhase(e) {
    const t = !!this.mobile
    t !== this.editing && ((this.editingStateChange = !0), (this.editing = t), this.cursorMesh.setVisible(this.editing))
  }
  deactivate() {
    this.sceneInfo.scene.removeChild(SceneChildType.Root, this.cursorMesh.container),
      this.renderToTexture.disposeRenderTarget2D(this.rttView),
      (this.editing = !1)
  }
  beforeRender() {
    this.editing &&
      ((this.hit = this.mobile ? this.pointer.lastIntersection : this.pointer.getIntersection()),
      this.hit && this.cursorMesh.onPositionUpdate(this.hit.point, this.hit.normal))
  }
  render() {
    if (this.editing && this.hit) {
      const { screenPosition: e } = P.q9(this.sceneInfo.cameraData, this.hit.point)
      this.renderIntersection(this.rttView, this.hit, e)
    }
  }
}
